import type { Context, Next } from "koa";
import { HttpException, RuntimeException } from "./exception";
import {
  JsonWebTokenError,
  NotBeforeError,
  TokenExpiredError,
} from "jsonwebtoken";
import {
  PrismaClientInitializationError,
  PrismaClientKnownRequestError,
} from "@prisma/generated-client/runtime/library";
// import { MaxRetriesPerRequestError } from "ioredis/built/errors";

export default () => {
  return async (ctx: Context, next: Next) => {
    let message = "success";
    try {
      await next(); // await controller -> await authorize -> await ... -> await authenticate -> await this
      if (typeof ctx.state.body === "undefined") {
        if (ctx.body) {
          ctx.status = 200;
        } else {
          ctx.status = 204;
        }
      } else {
        ctx.status = 200;
        ctx.body = { status: true, code: 0, message, data: ctx.state.body };
        ctx.state.body = null;
      }
    } catch (err) {
      let error = null;
      let status = 500;
      let code = -500;
      if (err instanceof RuntimeException) {
        status = 200;
        code = err.code;
        message = err.message;
        error = err.data;
        if (err instanceof HttpException) {
          status = err.code;
        }
      } else if (err instanceof TokenExpiredError) {
        // https://www.npmjs.com/package/jsonwebtoken#tokenexpirederror
        // 如果令牌已过期，则会抛出错误。
        status = 401;
        code = -1;
        message = "登录已过期";
        error = { expiredAt: err.expiredAt };
      } else if (err instanceof JsonWebTokenError) {
        // https://www.npmjs.com/package/jsonwebtoken#jsonwebtokenerror
        // “无效令牌”- 无法解析标头或有效负载
        status = 401;
        code = -2;
        message = "登录验证错误";
      } else if (err instanceof NotBeforeError) {
        // https://www.npmjs.com/package/jsonwebtoken#notbeforeerror
        // 如果当前时间早于 nbf 声明
        status = 401;
        code = -3;
        message = "登录未激活";
        error = { date: err.date };
      } else if (err instanceof PrismaClientInitializationError) {
        // 数据库服务不可用
        code = -4;
        message = "数据库服务不可用";
      } else if (err instanceof PrismaClientKnownRequestError) {
        // 该记录不存在，更新、删除不存在行就出现这个错误
        code = -44;
        message = "数据不存在";
      } /* else if (err instanceof MaxRetriesPerRequestError) {
        // Redis服务不可用
        code = -5;
        message = "Redis数据库不可用";
      }*/ else {
        code = 500;
        message = "服务器内部错误";
        console.log("\n", err.name, "\n");
        console.log(err);
      }
      ctx.status = status;
      ctx.body = { status: false, code, message, error, data: null };
    }
  };
};
